package beer.coder.walawala.gui.component;

import beer.coder.walawala.common.config.ItemConfigure;
import beer.coder.walawala.common.constant.IconType;
import beer.coder.walawala.gui.constant.GuiConstant;
import beer.coder.walawala.gui.handler.item.ItemActionHandler;
import beer.coder.walawala.gui.util.ImageUtil;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.paint.Paint;
import javafx.scene.text.TextAlignment;

/**
 * TODO
 *
 * @author amath0312
 * @version 1.0
 * @date 2019-10-25 00:29
 */
public class ItemButton extends BorderPane {

  ItemConfigure configure;
  Application application;
  ImageView shortcut;
  Label name;
  TextArea editor;
  Consumer<ItemButton> afterAction;
  Consumer<ItemButton> onConfigureChanged;
  Tooltip tooltip;
  boolean isEditing = false;

  public ItemButton(ItemConfigure configure,
      Consumer<ItemButton> afterAction,
      Consumer<ItemButton> onConfigureChanged,
      Application application) {
    this.configure = configure;
    this.afterAction = afterAction;
    this.onConfigureChanged = onConfigureChanged;
    this.application = application;
    init();
    setDragable();
  }


  private void init() {
    this.setOnDragOver((e) -> {
      System.out.println("!!!!!!!!!!!!!!");
    });
    isEditing = false;
    shortcut = new ImageView(loadImage());
    shortcut.setFitWidth(GuiConstant.ICON_SIZE);
    shortcut.setFitHeight(GuiConstant.ICON_SIZE);
    shortcut.prefWidth(GuiConstant.ICON_SIZE);
    shortcut.prefHeight(GuiConstant.ICON_SIZE);

    name = new Label(configure.getName());
    name.setPrefSize(GuiConstant.ICON_TEXT_WIDTH, GuiConstant.ICON_TEXT_HEIGHT);
    name.setTextAlignment(TextAlignment.CENTER);
    name.setAlignment(Pos.CENTER);
    name.setWrapText(true);

    editor = new TextArea(configure.getName());
    editor.setPrefSize(GuiConstant.ITEM_WRAPPER_WIDTH, GuiConstant.ICON_TEXT_HEIGHT);
    editor.setWrapText(true);
    editor.addEventFilter(KeyEvent.ANY, event -> {
      if (event.getEventType() == KeyEvent.KEY_PRESSED) {
        if (event.getCode() == KeyCode.ENTER) {
          event.consume();
        } else if (event.getCode() == KeyCode.ESCAPE) {
          event.consume();
        }
      } else if (event.getCode() == KeyCode.ENTER) {
        event.consume();
        commitRename();
      } else if (event.getCode() == KeyCode.ESCAPE) {
        event.consume();
        rollbackRename();
      }
    });

    editor.focusedProperty().addListener((observable, oldValue, newValue) -> {
      if (!newValue) {
        commitRename();
      }
    });

    tooltip = new Tooltip(configure.getName());
    this.setCenter(shortcut);
    this.setBottom(name);

    this.setPrefSize(GuiConstant.ITEM_WRAPPER_WIDTH, GuiConstant.ITEM_WRAPPER_HEIGHT);
    this.setPadding(new Insets(GuiConstant.ITEM_WRAPPER_PADDING));

    this.addEventHandler(
        MouseEvent.ANY,
        event -> {
          if (isEditing) {
            return;
          }

          if (event.getEventType() == MouseEvent.MOUSE_ENTERED) {
            this.setBackground(
                new Background(
                    new BackgroundFill(
                        Paint.valueOf("grey"),
                        new CornerRadii(5),
                        Insets.EMPTY)));
          } else if (event.getEventType() == MouseEvent.MOUSE_EXITED) {
            this.setBackground(Background.EMPTY);
          } else if (event.getEventType() == MouseEvent.MOUSE_CLICKED && event.getButton() == MouseButton.PRIMARY) {
            if (!getContainer().isDragging()) {
              Platform.runLater(() -> {
                ItemActionHandler.getInstance().action(this.application, this.configure);
                if (this.afterAction != null) {
                  this.afterAction.accept(this);
                }
              });
            }
          } else {
            event.consume();
          }
        });

    Tooltip.install(this, tooltip);
  }

  protected void setDragable() {
    AtomicBoolean pressed = new AtomicBoolean(false);
    AtomicInteger preX = new AtomicInteger(-1);
    AtomicInteger preY = new AtomicInteger(-1);
    this.addEventHandler(MouseEvent.MOUSE_PRESSED, (e) -> {
      preX.set((int) e.getSceneX());
      preY.set((int) e.getSceneY());
      pressed.set(true);
    });
    this.addEventHandler(MouseEvent.MOUSE_MOVED, (e) -> {
      if (pressed.get()) {
        int deltax = (int) e.getSceneX() - preX.get();
        int deltay = (int) e.getSceneY() - preY.get();
        this.setLayoutX(this.getLayoutX() + deltax);
        this.setLayoutY(this.getLayoutY() + deltay);
      }
    });
    this.addEventHandler(MouseEvent.MOUSE_RELEASED, (e) -> {
      pressed.set(false);
    });
  }

  public void rename() {
    this.setBottom(editor);
    this.editor.requestFocus();
    this.editor.selectAll();
    isEditing = true;
  }

  protected void commitRename() {
    changeName(editor.getText());
    setBottom(name);
    isEditing = false;
  }

  protected void rollbackRename() {
    changeName(configure.getName());
    setBottom(name);
    isEditing = false;
  }

  protected void changeName(String text) {
    configure.setName(text);
    name.setText(text);
    editor.setText(text);
    tooltip.setText(text);
    if (onConfigureChanged != null) {
      onConfigureChanged.accept(ItemButton.this);
    }
  }

  private Image loadImage() {
    Image iconImage;
    if (configure.getIconType() == IconType.EXE) {
      try {
        iconImage = ImageUtil
            .extractWindowsFileImage(new File(configure.getPath()), GuiConstant.ICON_SIZE, GuiConstant.ICON_SIZE);
        configure.setIconPath(ItemConfigure.DEFAULT_ICON_PATH);
        configure.setIconType(IconType.EXE);
      } catch (IOException ex) {
        iconImage = new Image(ItemConfigure.DEFAULT_ICON_PATH);
        configure.setIconPath(ItemConfigure.DEFAULT_ICON_PATH);
        configure.setIconType(IconType.FILE);
      }
    } else if (configure.getIconType() == IconType.FILE) {
      try {
        iconImage = new Image(configure.getIconPath());
      } catch (Exception ex) {
        iconImage = new Image(ItemConfigure.DEFAULT_ICON_PATH);
        configure.setIconPath(ItemConfigure.DEFAULT_ICON_PATH);
      }
    } else {
      iconImage = null;
    }
    return iconImage;
  }

  public void setContextMenu(ContextMenu menu) {
    this.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
      @Override
      public void handle(ContextMenuEvent event) {
        menu.show(ItemButton.this.shortcut, event.getScreenX(), event.getScreenY());
      }
    });
  }

  @Override
  public String toString() {
    return this.configure.getName();
  }

  protected ItemsFlowPane getContainer() {
    return (ItemsFlowPane) getParent();
  }

  public ItemConfigure getItemConfigure() {
    return configure;
  }
}
